/*
 * Copyright 1992-4   BG Systems, Inc.
 * init_lv.c
 *
 * Routine to init a Rev 3.0 Box
 *
 * Author         Date       Comments
 * John Green     15-Oct-94  Major revision for v 3.0 EPROM
 * John Green     21-Oct-94  Broken out of fblib.c
 * John Green     14-Jan-95  Added acknowledge
 * John Green     01-Feb-95  Final touches for rev 3.0 release
 * John Green     21-Feb-95  Fixed bug when init_lv() called again
 * John Green     15-Mar-95  Fixed dig out setup bug
 * John Green     03-Apr-95  Allow 2.4 EPROM
 * John Green     17-Apr-95  return() rather than exit() if setup fails
 * John Green     27-Jun-95  Added support for OB1K-112 board
 * John Green     02-Oct-95  Added support for outputs for OB1K-112 board
 * John Green     03-Mar-97  Minor cleaning
 * John Green     20-Oct-97  Update for 3.07
 * John Green     06-Nov-97  Final cleanup for 3.07
 * John Green     14-Nov-97  Minor bug fix (initialize c4=0 etc.)
 * John Green     20-Nov-97  Add encoder setup
 */


#include <stdio.h>
#include <stdlib.h>

#include "lv3.h"

static char SccsId[] = "@(#)init_lv.c	1.21 24 Nov 1997";

extern RS_ERR rs_err;

extern int w_lv(int, char *);
extern int get_ack(int );
extern int set_baud(int, int );
extern int check_setup(bglv *);

void compute_channels(bglv *);

int init_lv(bglv *bgp)
{
   char c1, c2, c3;
   char c4, c5, c6;
   char c7, c8, c9;
   char str[32];
   int  st;

   st = check_setup(bgp);
   if ( st < 0 )
      return(st);

/*
 *  Compute the number of channels requested, and the 
 *  appropriate string length.
 */

   compute_channels(bgp);

/*
 *  Set the string length for receiving data
 */
   bgp->str_len  = 2 + (2*bgp->n_analog_in) + (bgp->n_dig_in/4) 
                     + (bgp->n_enc*4);

/*
 *  Set the first character of the setup string.
 *  This varies depending on the EPROM revision
 */

   if ( bgp->Rev.major == 2 )
   {
      if ( bgp->Rev.minor == 2 )
         str[0] = 'R';
      else if ( bgp->Rev.minor == 3 )
         str[0] = 'r';
      else
         return (-1);
   }
   else if ( bgp->Rev.major == 3 )
   {
      if ( bgp->Rev.bug <= 6 )
         str[0] = 's';
      else if ( bgp->Rev.bug >= 7 )
         str[0] = 'c';
      else
      {
         printf("EPROM Revision not valid : Contact BG Systems\n");
         return(-1);
      }
   }
   

/*
 *  The following comments show how the various characters
 *  are to be set.  As the LV series has progressed, some 
 *  characters have had their meaning changed.  This is why
 *  there are numerous tests to see which EPROM we are talking to.
 *
 *  If multiplex digital inputs selected, overwrite c2 and set c3
 *  c1:
 *    bits 1-4 for analog inputs (1-4)
 *    bits 5-8 for baud rate
 *  c2:
 *    bits 1-4 for analog inputs (5-8)
 *    bits 5-7 for dig input (unless MP board)
 *    bits 5-7 for MP input board type selection
 *  C3:
 *    bits 1-3 for analog outputs (1-3)
 *    bits 5-7 for dig output selection
 *    bit  4   for MP request (3.06 and lower)
 *    bit  4   for analog output 4 (3.07 and higher)
 *    bits 5-7 for MP input board selection
 *  c4:
 *    bits 1-4 for analog outputs (5-8)
 *    bit  5   for MP request (3.07 and higher)
 *  c5:
 *    bits 1-4 encoder 1-4 selection on/off
 *  c6:
 *    bits 1-4 encoder 1-4 selection inc/abs
 *  c7:
 *    bits 1-4 encoder 5-8 selection on/off
 *  c6:
 *    bits 1-4 encoder 5-8 selection inc/abs
 */
   c1 =  bgp->baud;
   c1 |= (bgp->analog_in & 0xf);

   c2 = (bgp->analog_in & 0xf0) >> 4;

   if ( bgp->Rev.major == 2 )
      c2 |=  bgp->dig_in;
   else if ( bgp->Rev.major == 3 )
   {
      c3 = bgp->analog_out & 0xf;
      c4 = 0x0;
      c5 = 0x0;
      c6 = 0x0;
      c7 = 0x0;
      c8 = 0x0;

      if ( bgp->mp_dig_in != 0 || bgp->mp_dig_out != 0 )
      {
         if ( bgp->mp_dig_in == MD112 )
            c2 |= MP112i;
         else if ( bgp->mp_dig_out == MD112 )
            c2 |= MP112o;
         else
            c2 |= MP56io;

         if ( bgp->Rev.bug == 6 )
            c3 |= MPDIG; 
         else if ( bgp->Rev.bug >= 7 )
            c4 |= (MPDIG << 1);
      }
      else 
      {
         c2 |= bgp->dig_in;
         c3 |= bgp->dig_out & 0xf0;
      }

      if ( bgp->Rev.bug >= 7 )
      {
         c4 |= ( bgp->analog_out & 0xf0) >> 4;
         c5 = bgp->enc_sel & 0x0f;
         c6 = bgp->enc_type & 0x0f;
         c7 = (bgp->enc_sel & 0xf0) >> 4;
         c8 = (bgp->enc_type & 0xf0) >> 4;
      }
   }
 
/*
 *  Now assign the setup characters to the string
 *  For rev 2.2 EPROMS use no offset
 *  For all other EPROMs add the offset (0x21) to avoid flow control
 *  Rev 2.x ends with str[3]
 *  Rev 3.06 and lower ends with str[4]
 *  Rev 3.07 and higher can set up to str[9]
 */
   if ( bgp->Rev.major == 2 && bgp->Rev.minor == 2 )
   {
      str[1] = c1;
      str[2] = c2;
   }
   else
   {
      str[1] = c1 + OFFSET;
      str[2] = c2 + OFFSET;
   }
   if ( bgp->Rev.major == 2 )
      str[3] = '\0';
   else if (bgp->Rev.major >= 3 )
   {
      str[3] = c3 + OFFSET;
      if (bgp->Rev.bug >= 7 )
      {
         str[4] = c4 + OFFSET;
         str[5] = c5 + 0x21;
         str[6] = c6 + 0x21;
         str[7] = c7 + 0x21;
         str[8] = c8 + 0x21;
         str[9] = '\n';
         str[10] = '\0';
      }
      else
          str[4] = '\0';
   }

/*
 *  And now send the string
 */
   st = w_lv(bgp->sp_fd, str);

/*
 *  Make sure that the LV got the setup !
 */
   if (bgp->Rev.major >= 3 )
   {
      st = get_ack(bgp->sp_fd);
/*
 *  If we have a rev 3.00 eprom, just don't check the return
 *  value - just proceed and assume things are OK.
 *  (Bug fixed in 3.01)
 */
      if ( bgp->Rev.bug != 0 )
      {
         if ( st < 0 )
            return(st);
      }
   }
 
   st = set_baud(bgp->sp_fd, bgp->baud);
 
   return(0);
}

void compute_channels(bglv *bgp)
{
   int i;
/*
 *  Analog inputs
 */
   bgp->n_analog_in = 0;
   for ( i=0; i < 8; i++)
      if ( (bgp->analog_in >> i) & 0x1 )
         bgp->n_analog_in++;

/*
 *  Digital inputs
 */

   if ( bgp->mp_dig_in == 0 )
   {
      switch(bgp->dig_in)
      {
       case 0x0:
         bgp->n_dig_in = 0;
         break;
       case 0x10:
       case 0x20:
       case 0x40:
         bgp->n_dig_in = 8;
         break;
       case 0x30:
       case 0x50:
       case 0x60:
         bgp->n_dig_in = 16;
         break;
       case 0x70:
         bgp->n_dig_in = 24;
         break;
      }
   }
   else
   {
      switch(bgp->mp_dig_in)
      {
       case MD16:
         bgp->n_dig_in = 16;
         break;
       case MD32:
         bgp->n_dig_in = 32;
         break;
       case MD48:
         bgp->n_dig_in = 48;
         break;
       case MD56:
         bgp->n_dig_in = 56;
         break;
       case MD64:
         bgp->n_dig_in = 64;
         break;
       case MD80:
         bgp->n_dig_in = 80;
         break;
       case MD96:
         bgp->n_dig_in = 96;
         break;
       case MD112:
         bgp->n_dig_in = 112;
         break;
      }
   }

/*
 *  Digital outputs
 */

   if ( bgp->mp_dig_out == 0 )
   {
      switch(bgp->dig_out)
      {
       case 0x0:
         bgp->n_dig_out = 0;
         break;
       case 0x10:
       case 0x20:
       case 0x40:
         bgp->n_dig_out = 8;
         break;
       case 0x30:
       case 0x50:
       case 0x60:
         bgp->n_dig_out = 16;
         break;
       case 0x70:
         bgp->n_dig_out = 24;
         break;
      }
   }
   else
   {
      switch(bgp->mp_dig_out)
      {
       case MD16:
         bgp->n_dig_out = 16;
         break;
       case MD32:
         bgp->n_dig_out = 32;
         break;
       case MD48:
         bgp->n_dig_out = 48;
         break;
       case MD56:
         bgp->n_dig_out = 56;
         break;
       case MD64:
         bgp->n_dig_out = 64;
         break;
       case MD80:
         bgp->n_dig_out = 80;
         break;
       case MD96:
         bgp->n_dig_out = 96;
         break;
       case MD112:
         bgp->n_dig_out = 112;
         break;
      }
   }

/*
 *  Analog outputs
 */
   bgp->n_analog_out = 0;
   if ( bgp->analog_out > 0 )
   {
      for ( i=0; i < 8; i++)
         if ( (bgp->analog_out >> i) & 0x1 )
            bgp->n_analog_out++;
   }

/*
 *  Encoders
 */
   bgp->n_enc = 0;
   for ( i = 0; i < 8; i++ )
   {
      if ( (bgp->enc_sel >> i) & 0x1 )
         bgp->n_enc++;
   }
}
